package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	_ "gitee.com/liuxiaowei123/vblog-01/vblog-01/vblog/apps"
	"gitee.com/liuxiaowei123/vblog-01/vblog-01/vblog/conf"
	"gitee.com/liuxiaowei123/vblog-01/vblog-01/vblog/ioc"
	"gitee.com/liuxiaowei123/vblog-01/vblog-01/vblog/protocol"
)

func main() {
	// 1.加载配置
	err := conf.LoadConfigToml("etc/etc.toml")
	if err != nil {
		// 错误写法：return err
		log.Fatal(err)
	}

	// 2.初始化模块
	//01.user controller
	// usercontoller := userimpl.NewUserServiceImpl()
	//02.token controller
	// tokencontroller := tokenimpl.NewTokenServiceImpl(usercontoller)
	// 改进 实现user controller、token controller的初始化
	ioc.Controller().Init()
	//03.api handler
	// apicontroller := api.NewTokenApiHandler(tokencontroller)
	// 改进
	// apicontroller := api.NewTokenApiHandler(ioc.Controller().Get(token.Appname).(token.Service))
	ioc.ApiHandler().Init()

	// 3.注册到路由
	// r := gin.Default()
	// apicontroller.Registry(r)
	// 接口改进
	// r.Group是用于创建路由组的功能,允许将相关的路由路径组合在一起
	// ioc.ApiHandler().RouteRegistry(r.Group("/api/vblog"))

	// 更新代码
	// 01.用goroutine后台运行http server
	go func() {
		err := protocol.NewHttpServer().Run()
		if err != nil {
			// 无法直接从goroutine返回一个错误到调用者,通常的做法是使用通道(channel)在goroutine和主线程之间传递结果
			// 错误代码：return err
			fmt.Printf("http server error, %s\n", err)
		}
	}()

	// 定义chanel，并监视其中的signals
	// os.Signal 表示操作系统信号的类型
	ch := make(chan os.Signal, 1)
	//  下面这行代码告诉操作系统当接收到SIGTERM、SIGINT、SIGHUP或SIGQUIT这四种信号时，将信号发送到ch这个通道。
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP, syscall.SIGQUIT)

	// 02.从chanel中取值，也就是等待信号
	c := <-ch
	fmt.Println(c)

	// 03.设置超时时长，关闭程序；这里并没有做超时处理
	// cancel 是一个取消函数。当你想提前结束与这个上下文相关的操作时，你可以调用这个取消函数
	ctx, cacel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cacel()
	// 正常这里应该用select，来做上下文超时处理
	protocol.NewHttpServer().Close(ctx)

	// 04.关闭程序后的处理工作
	fmt.Println("清理工作")

	// 4.启动程序
	// Address := fmt.Sprintf("%s:%d", conf.C.Api.Apihost, conf.C.Api.Apiport)
	// fmt.Printf("HTTP API监听地址: %s", Address)
	// // r.Run(addr ...string)函数用于启动一个HTTP服务器，并监听指定的地址以接受请求并处理它们
	// err = r.Run(Address)
	// log.Fatal(err)

}

// 关于context.WithTimeout的示例
/*我们创建了一个带有3秒超时时间的上下文ctx。然后，我们启动了一个goroutine执行doSomething函数，
该函数在2秒后取消上下文。在主goroutine中，我们使用select语句监听超时和上下文的取消信号。如果超过4秒仍未收到任何信号，
则输出"操作超时"；如果收到取消信号，则输出"操作完成"。
*/
// func main() {
//  ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
//  defer cancel()

//  done := ctx.Done()
//  go doSomething(ctx)

//  select {
//  case <-time.After(4 * time.Second):
//  fmt.Println("操作超时")
//  case <-done:
//  fmt.Println("操作完成")
//  }
// }

// func doSomething(ctx context.Context) {
//  time.Sleep(2 * time.Second) // 模拟一些操作
//  cancel() // 取消上下文
// }
